﻿//
// Arduino Volt Meter (c) Joe Pardue 8/20/09
//
// WARNING: This software is for playing with electricity. Electricity is 
// that stuff that jumps out of the clouds making a big boom and is more
// than capable of blasting a tree or golfer into blackened smoking bits.
// Even though this is intended for folks using low voltages, I have no 
// doubt someone somewhere will tie this to a kite with a metallic string and
// fly it in a thunder storm and then bless me out (if they survive) because
// their stuff got blown all to Hell. Forutnately I am protected by a level
// of personal assets below the threshold of even the hungriest ambulance
// chaser so I'm not too worried about getting sued, and anyway I'm so old
// now that I might actually enjoy becoming a Darwinian Fundamentalist and
// removing some folks from the gene pool.  
// 
//  This work is entirely by Joe Pardue (except for the major portions he
//  stole and forgot to attribute).
//
//  This software is not warrented in any way what-so-ever. It WILL screw
//  something up and will kill someone after doing serious property
//  damage. 
//  You've been warned. (Twice now) Ah, yes I feel much better now.
//
// Please post questions to www.AVRFreaks.net and if the thread title is clear,
// I might see it there, and if the question isn't clearly covered in the 
// associated documentation, I might even answer it.
//

// This code is extracted from ideas and code in my book: 
// "Virtual Serial Port Cookbook" that you can get from 
// either www.smileymicros.com or Amazon
// There is preview materials on my website that will take you 
// up to building a Simple Terminal program.

//
// Unplugging the USB while the serialPort is open can cause unpredictable
// behavior and may require the user to close and reopen the program.
//


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using PortSet;
using DUD; // Detect USB Disconnect

namespace AVM
{
    public partial class Form1 : Form
    {
        //PortSettings portSet = new PortSettings();

        bool portIsOpen = false;

        static Double maxVoltage = 5.0;
        static Double maxADC = 1023.0;
        Double VoltsPerADC = maxVoltage / maxADC;


        private USBDisconnectDetector usbDisconnectDetector = null;

        public Form1()
        {
            InitializeComponent();

            //label1.Visible = false;

            usbDisconnectDetector = new USBDisconnectDetector();
            usbDisconnectDetector.USBRemoved += new USBDisconnectDetectorEventHandler(OnUSBRemoved);
        }


        // Called by DriveDetector after removable device has been unpluged 
        private void OnUSBRemoved(object sender, USBDisconnectDetectorEventArgs e)
        {
            if (portIsOpen)// we think the port is open
            {
                //if (!serialPort1.IsOpen) // but it isn't
                //{
                    //timer1.Enabled = false;
                    serialPort1.Close();
                    serialPort1.Dispose();
                    //portSet.Close();

                    openPortToolStripMenuItem.Enabled = false;
                    portIsOpen = false;
                    richTextBoxReceive.Text = "USB unplugged.\nClosing the port.";
                //}
            }


            //MessageBox.Show("USB Disconnect");
            //label1.Visible = true;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // Preset for Arduino
/*            portSet.selectedBaudrate = 19200;
            portSet.selectedDataBits = 8;
            portSet.selectedHandshaking = System.IO.Ports.Handshake.None;
            portSet.selectedParity = System.IO.Ports.Parity.None;
            portSet.selectedStopBits = System.IO.Ports.StopBits.One;

            //serialPort1.Open();
            serialPort1.BaudRate = portSet.selectedBaudrate;
            serialPort1.DataBits = portSet.selectedDataBits;
            serialPort1.Handshake = portSet.selectedHandshaking;
            serialPort1.Parity = portSet.selectedParity;
            serialPort1.StopBits = portSet.selectedStopBits;
*/
            richTextBoxReceive.Text = "Input from Arduino\n";
            openPortToolStripMenuItem.Enabled = false;

        }

        private void selectDeviceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PortSettings portSet = new PortSettings();
            
            //portSet.initializePortSettings();

            if (serialPort1.IsOpen)
            {
                serialPort1.Close();
                serialPort1.Dispose();
                openPortToolStripMenuItem.Enabled = false;
                portIsOpen = false;
                MessageBox.Show("Attempted to select device when a device was open.");
            }
            else
            {

                // Preset for Arduino
                portSet.selectedBaudrate = 9600;
                portSet.selectedDataBits = 8;
                portSet.selectedHandshaking = System.IO.Ports.Handshake.None;
                portSet.selectedParity = System.IO.Ports.Parity.None;
                portSet.selectedStopBits = System.IO.Ports.StopBits.One;

                if (portSet.ShowDialog() == DialogResult.OK)
                {
                        serialPort1.PortName = portSet.selectedPort;
                        serialPort1.BaudRate = portSet.selectedBaudrate;
                        serialPort1.DataBits = portSet.selectedDataBits;
                        serialPort1.Handshake = portSet.selectedHandshaking;
                        serialPort1.Parity = portSet.selectedParity;
                        serialPort1.StopBits = portSet.selectedStopBits;

                        serialPort1.Open();
                        portIsOpen = true;

                        openPortToolStripMenuItem.Enabled = true;
                        openPortToolStripMenuItem.Text = "Close Port";
                }
                else
                {
                    if(serialPort1.IsOpen)
                    {
                        serialPort1.Close();
                        serialPort1.Dispose();
                        openPortToolStripMenuItem.Enabled = false;
                        portIsOpen = false;
                        richTextBoxReceive.Text = "Port Setting Failure.\nClosing the port.";
                    }
                }
            }
        }

        #region Receive functions

        // we want to have the serial port thread report back data received, but to display
        // that data we must create a delegate function to show the data in the richTextBox

        // define the delegate 
        public delegate void SetText();
        // define an instance of the delegate
        SetText setText;

        // create a string that will be loaded with the data received from the port
        public string str = "";
        // JWP 4/28/07 added public byte for receiving bytes
        public byte byt = 0;

        // note that this function runs in a separate thread and thus we must use a delegate in order
        // to display the results in the richTextBox.
        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
              // instantiate the delegate to be invoked by this thread
                setText = new SetText(mySetText);

                // load the data into the string
                try
                {
                    str = serialPort1.ReadLine();//.ReadExisting();
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show("Error - port_DataReceived Exception: " + ex);
                }

                // invoke the delegate in the MainForm thread
                this.Invoke(setText);
        }

        // create the instance of the delegate to be used to write the received data to the richTextBox
        public void mySetText()
        {
            int myADC = 0;
            Double myVolts = 0;

            // Show the ADC reading in the text box
            richTextBoxReceive.Text += str.ToString() + "\n";
            
            // Convert received string to integer
            int.TryParse(str, out myADC);

            // Calculate volts
            myVolts = ((Double)myADC * VoltsPerADC);

            // Show voltage on label to two decimal places
            labelVolt.Text =  myVolts.ToString("0.00");
        }

        // This rigaramole is needed to keep the last received item displayed
        // it kind of flickers and should be fixed
        private void richTextBoxReceive_TextChanged_1(object sender, EventArgs e)
        {
            moveCaretToEnd();
        }

        private void moveCaretToEnd()
        {
            richTextBoxReceive.SelectionStart = richTextBoxReceive.Text.Length;
            richTextBoxReceive.SelectionLength = 0;
            richTextBoxReceive.ScrollToCaret();
        }

        #endregion

        // Reset the Arduino
        // if you want to understand this, condider purchasing my 
        // Virtual Serial Port Cookbook from either www.smileymicros.com
        // or Amazon
        private void button1_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen)
            {
                serialPort1.DtrEnable = true;
                serialPort1.DtrEnable = false;
                serialPort1.DtrEnable = true;
            }

        }

        private void openPortToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openPort();
        }

        private void openPort()
        {
            try
            {
                if (serialPort1.IsOpen)
                {
                    serialPort1.Close();
                    serialPort1.Dispose();
                    openPortToolStripMenuItem.Text = "Open Port";
                    portIsOpen = false;
                }
                else
                {
                    serialPort1.Open();
                    openPortToolStripMenuItem.Text = "Close Port";
                    portIsOpen = true;
                }
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("Error - openPortToolStripMenuItem_Click Exception: " + ex);
            }
        }
    }
}
